// The Karel's city control presenter

/// <reference path="../typings/jquery/jquery.d.ts" />
/// <reference path="../typings/jquery/jqueryui.d.ts" />

// import interfaces
import I = require("./Interfaces");

// import debugging city renderer
import R = require("./DebugCityRenderer");

// import the execution engine
import Exec = require("../MiddleLayer/Execution/ExecutionEngine");

// import robot Karel
import Karel = require("../MiddleLayer/Execution/RobotKarel");

// import the city
import City = require("../MiddleLayer/Execution/City");

// import MessageBox
import MsgBox = require("./MessageBox");

// import dialogs
import Dlg = require("./Dialog");

enum eItemType { None, Karel, Wall, PutMark, PickMark };

// City widget class
export class CityWidget {

    // Karel's city renderer
    private mRenderer: R.DebugCityRenderer;

    // module references
    private mEngine: Exec.ExecutionEngine;
    private mCity: City.City;
    private mKarel: Karel.RobotKarel;

    // UI dependencies
    private mCommandLine: I.ICommandLine;

    // item type to be put by click event
    private mItemType: eItemType;

    // the canvas element which the city is drawn in
    private mCanvas; HTMLCanvasElement;

    // constructor
    public constructor() {
        this.mItemType = eItemType.None;

        // init city renderer
        this.mRenderer = new R.DebugCityRenderer("idCanvas");
        this.mCanvas = document.getElementById("idCanvas");

        // set module references
        this.mEngine = Exec.ExecutionEngine.Instance;
        this.mKarel = Karel.RobotKarel.Instance;
        this.mCity = City.City.Instance;

        // builds the control
        this.BuildControl();
    }

    // return the city renderer
    public get CityRenderer(): I.ICityRenderer {
        return this.mRenderer;
    }

    // sets the UI dependencies
    public SetDependencies(commandLine: I.ICommandLine) {
        this.mCommandLine = commandLine;
    }

    // builds the control
    private BuildControl(): void {
        var that = this;

         // build the city and Karel toolbars
        //////////////////////////////////////////////
        $("#idKarelToolbar button").button();
        $("#idCityToolbar button").button();
        $("#idCitySwitch").buttonset();
        $("#idSpeed").slider(
            {
                step: 10,
                min: 50,
                max: 1000,
                value: that.mEngine.GetInterval(),
                slide: function (event, ui) {
                    var speed = 1050 - parseInt(ui.value);
                    that.mEngine.SetInterval(speed);
                }
            });


         // add button handlers
        /////////////////////////////////////////////

        // Pause button handler
        $("#idPauseCommand").click(function () {
            if (that.mEngine.IsRunning) {
                that.mEngine.Pause();
                that.CityRenderer.Render();
            }
        });

        // Continue button handler
        $("#idContinueCommand").click(function () {
            if (that.mEngine.IsPaused) {
                that.mEngine.Resume();
                that.CityRenderer.Render();
            }
        });

        // Stop Button handler
        $("#idStopCommand").click(function () {
            if (that.mEngine.IsRunning) {
                that.mEngine.Terminate();               

                // save the city
                that.mKarel.Save();

                // update the UI
                that.CityRenderer.Render();
                that.mCommandLine.Update();
            }
        });

        // Clear City handler
        $("#idClearCityCommand").click(function () {
            // if engine running or paused, exit
            if (that.mEngine.IsRunning || that.mEngine.IsPaused)
                return;

            // ask for confirmation
            MsgBox.MessageBox.Instance.Confirm("ShouldClearCity", "Confirmation", function (result) {
                // if confirmed
                if (result == MsgBox.eConfirmResult.Yes) {
                    // clear the city and move Karel home
                    that.mCity.ClearCity();
                    that.mKarel.MoveHome();

                    // save the city
                    that.mKarel.Save();
                    that.mRenderer.Render();
                }
            });          
        });

        // Collect marks handler
        $("#idCollectMarksCommand").click(function () {
            // if engine running or paused, exit
            if (that.mEngine.IsRunning || that.mEngine.IsPaused)
                return;

            // ask for confirmation
            MsgBox.MessageBox.Instance.Confirm("ShouldCollectMarks", "Confirmation", function (result) {
                // if confirmed
                if (result == MsgBox.eConfirmResult.Yes) {
                    // clear the city
                    that.mCity.CollectAllMarks();

                    // save the city
                    that.mKarel.Save();

                    that.mRenderer.Render();
                }
            });
        });

        // Load the city from a file
        $("#idLoadCityCommand").click(function () {
            // if engine running or paused, exit
            if (that.mEngine.IsRunning || that.mEngine.IsPaused)
                return;

            // load city anonymous function
            var loadCity = function () {
                Dlg.Dialog.Instance.ShowCityUploadDialog(function (file) {

                    // read the file asynch
                    var reader = new FileReader();
                    reader.onload = function (e) {
                        var sourceCode = reader.result;

                        // invoke import to the dictionary
                        that.mKarel.Import(sourceCode);

                        // save it
                        that.mKarel.Save();

                        // refresh the command list
                        that.mRenderer.Render();

                    }
                    reader.onerror = function (e) {
                        MsgBox.MessageBox.Instance.ShowModal("CityCorrupted", "Error");
                    }
                    reader.readAsText(file);
                });
            }

            // TO-DO: place confirmation when required
            loadCity();
        });

        // Save the city to a file
        $("#idSaveCityCommand").click(function () {
            // if engine running or paused, exit
            if (that.mEngine.IsRunning || that.mEngine.IsPaused)
                return;

            // get the complete source code of the city
            var sourceCode = that.mKarel.Export();

            // POST it to the server
            $.post("/Pages/Upload.aspx",
                {
                    "Content": sourceCode,
                    "Filename": "mesto.txt"
                }, function (data, textStatus, jqXHR) {
                    // run the download dialog
                    Dlg.Dialog.Instance.ShowCityDownloadDialog();

                }).fail(function () {
                    MsgBox.MessageBox.Instance.ShowModal("InternetError", "Error");
                });                  

        });

        // changing the item type handler
        $("#idCitySwitch :radio").click(function (e) {
            var type = $(this).attr("data-type");
            that.mItemType = eItemType.None;

            switch (type) {
                case "Karel":
                    that.mItemType = eItemType.Karel;
                    break;
                case "Wall":
                    that.mItemType = eItemType.Wall;
                    break;
                case "Put":
                    that.mItemType = eItemType.PutMark;
                    break;
                case "Pick":
                    that.mItemType = eItemType.PickMark;
                    break;
            }
        });

        // left mouse button click on the canvas
        $(this.mCanvas).click(function (e) {
            // if engine running or paused, exit
            if (that.mEngine.IsRunning || that.mEngine.IsPaused || that.mItemType == eItemType.None)
                return;

            // get mouse position when clicked
            //var parentOffset = $(this).parent().offset();
            var thisOffset = $(this).offset();
            var mouseX = e.pageX - thisOffset.left;
            var mouseY = e.pageY - thisOffset.top;

            // get field by mouse pointer
            var field = that.mRenderer.GetFieldByMouse(mouseX, mouseY);
            if (field == null)
                return;

            // choose action to do in the city
            switch (that.mItemType) {
                case eItemType.Karel:                    
                    // move Karel if not wall at that field
                    if (that.mCity.IsWall(field[0], field[1]) == false) {                        
                        that.mKarel.SetPosition(field[0], field[1]);
                    }
                    break;
                case eItemType.Wall:
                    // make wall if not Karel at that field
                    if (!(that.mKarel.Row == field[0] && that.mKarel.Col == field[1])) {
                        that.mCity.MakeWall(field[0], field[1]);
                    }
                    break;
                case eItemType.PutMark:
                    // put mark if the filed is not full
                    if (that.mCity.IsWall(field[0], field[1]) == false) {
                        if (that.mCity.GetNumberOfMarks(field[0], field[1]) < that.mKarel.MaxMarks) {
                            that.mCity.PutMark(field[0], field[1]);
                        }
                    }
                    break;
                case eItemType.PickMark:                   
                    // pick mark if there is any
                    if (that.mCity.IsWall(field[0], field[1]) == false) {
                        if (that.mCity.GetNumberOfMarks(field[0], field[1]) > 0) {
                            that.mCity.PickMark(field[0], field[1]);
                        }
                    }
                    break;             
            }

            // save the city
            that.mKarel.Save();

            // re-render the city
            that.mRenderer.Render();          
        });

        // right mouse click on the city - means clear the field
        $(this.mCanvas).bind("contextmenu", function (e) {
            // if engine running or paused, exit
            if (that.mEngine.IsRunning || that.mEngine.IsPaused)
                return;

            // get mouse position when clicked
            var thisOffset = $(this).offset();
            var mouseX = e.pageX - thisOffset.left;
            var mouseY = e.pageY - thisOffset.top;

            // get field by mouse pointer
            var field = that.mRenderer.GetFieldByMouse(mouseX, mouseY);
            if (field == null)
                return;

            // clear the field
            that.mCity.ClearField(field[0], field[1]);

            // save the city
            that.mKarel.Save();

            // re-render the city
            that.mRenderer.Render();          

            // do not show browser context menu
            e.preventDefault();
        });    

        // set active item type
        $("#idCitySwitch #radio1").click();

    }

    // adapts the layout of the control to the new window size
    public LayoutControl(): void {
        // compute left pane item heights
        var leftPane = document.getElementById("leftPane");
        var width = $(leftPane).width();
        var height = $(leftPane).innerHeight() - $("#idKarelToolbar").outerHeight() - $("#idCityToolbar").outerHeight();
        $("#idCity").outerHeight(height);

        // get inner heights
        width = $("#idCity").innerWidth();
        height = $("#idCity").innerHeight();

        // compute canvas size
        var canvasSize = Math.min(width, height);

        // set canvas size
        var canvas = <HTMLCanvasElement>document.getElementById("idCanvas");
        $(canvas).attr("width", canvasSize);
        $(canvas).attr("height", canvasSize);

        // center the canvas in the left panel
        var x = (width - canvasSize) / 2;
        var y = (height - canvasSize) / 2;
        $(canvas).css("position", "relative");
        $(canvas).css("left", x);
        $(canvas).css("top", y);

        // re-render the city
        this.mRenderer.Render();
    }
}
